# -*- coding: utf8 -*-
from threading import Timer

from soccerbots.net import Server as NetServer
from phisics2 import Phisics
from structs import *
import states

FPS = 25
VLM = 500
VAM = 80

class Server:
    def __init__(self):
        properties = {}
        properties['FLM'] = 1
        properties['FAM'] = 2
        properties['PR'] = 1
        properties['PP'] = 2
        properties['FT'] = 2
        properties['VLM'] = VLM
        properties['VAM'] = VAM

        self.part = 1
        self.net_server = NetServer(self, properties)
        #self.phisics = Phisics(states.iniState(atacant=1, part=1))
        self.phisics = Phisics()

        # Periodic task
        self.timeout = 1./FPS

        self.current_state = None 
        self.teams_movements = {} # Indexed by client ID
        self.clients_ids = []
        self.teams = []
        self.marcador = [0, 0]
        self.time = 0
        self.timer_running = False

        self.ready = {}

        self.net_server.start()

    def clientJoined(self, id):
        self.ready[id] = 0

        if len(self.clients_ids)<2:
            self.clients_ids.append(id)
            #self.teams_movements[id] = TeamMovement()
            print 'Reached client with id:',id
            if len(self.clients_ids)==2:
                '''
                  Enviar els estats inicials. L'equip amb ID petit és el primer
                  atacant.
                '''
                self.teams = [min(self.clients_ids),max(self.clients_ids)]
                print 'TEAMS VECTOR:',self.teams
                self.current_state = states.iniState(atacant=1, part=self.part)
                #self.current_state.ball.position = (-1100,1000)
                #self.current_state.ball.linearVel = 1000
                #self.current_state.ball.direction = 180
                self.net_server.sendInitState(self.teams[0], 1, 1, self.current_state)
                self.net_server.sendInitState(self.teams[1], 2, 0, self.current_state)
        else:
            print 'Max number of clients reached !'
            raise RuntimeError

    def eventReceived(self, id, event):
        if event.type == Event.XIULET:
            self.clock()

        elif event.type == Event.INICI:
            self.ready[id] = 1
            if sum(self.ready.values()) == 2:
                print 'Starting timer ...'
                self.clock()

        elif event.type == Event.GOL:
            self.timer.cancel()

            if self.current_state.ball.position[0] < 0:
                marcat = 3-self.part
            else:
                marcat = self.part

            self.marcador[marcat-1] += 1
            self.net_server.golAck(self.marcador)
            
            atacant = 3-marcat
            print 'atacant:',atacant
            print 'marcat:',marcat
            if self.part==1:
                fpart = atacant
            else:
                fpart = 3-atacant
            self.current_state = states.iniState(atacant=atacant, part=fpart)
            self.net_server.sendInitState(self.teams[0], 1, 2-atacant, self.current_state)
            self.net_server.sendInitState(self.teams[1], 2, 2-marcat, self.current_state)
            self.update_phisics()

        elif event.type == Event.FAULT:
            self.timer.cancel()
            self.net_server.faultAck(event.team, event.fault)

            if event.fault == Event.PENALTY:
                atacant = 3-event.team
                self.current_state = states.penaltyState(atacant=atacant, part=self.part)
                self.net_server.sendInitState(self.teams[0], 1, 0, self.current_state)
                self.net_server.sendInitState(self.teams[1], 2, 0, self.current_state)
                
            elif event.fault == Event.FREE_KICK:
                atacant = 3-event.team
                self.current_state = states.freekickState(atacant=atacant, part=self.part)
                self.net_server.sendInitState(self.teams[0], 1, 0, self.current_state)
                self.net_server.sendInitState(self.teams[1], 2, 0, self.current_state)
                
            elif event.fault == Event.FREE_BALL:
                x,y = self.current_state.ball.position
                y-=900
                if x>=0 and y>=0: q=1
                elif x<0 and y>=0: q=2
                elif x<0 and y<0: q=3
                elif x>=0 and y<0: q=4
                self.current_state = states.freeballState(q, self.part)
                self.net_server.sendInitState(self.teams[0], 1, 0, self.current_state)
                self.net_server.sendInitState(self.teams[1], 2, 0, self.current_state)

            self.update_phisics()

            #TODO: Send new state

        elif event.type == Event.FIPART:
            self.timer.cancel()
            self.net_server.fiPartAck()

            self.part += 1
            self.current_state = states.iniState(atacant=2, part=self.part)
            self.net_server.sendInitState(self.teams[0], 1, 0, self.current_state)
            self.net_server.sendInitState(self.teams[1], 2, 1, self.current_state)

            self.update_phisics()
            
        elif event.type == Event.FIPARTIT:
            self.timer.cancel()
            
            self.net_server.fiPartitAck()
            self.net_server.finalize()

    def update_phisics(self):
        self.phisics.compute(self.current_state, 0, relocate=1)

    def movementReceived(self, movement):
        self.teams_movements[movement.id] = movement

    def getMovements(self, id):
        try:
            return self.teams_movements[self.teams[id]]
        except:
            return TeamMovement()

    def applyMovements(self):
        k = self.teams_movements.keys()
        if len(k)==2:
            movms = [self.getMovements(0), self.getMovements(1)]
            teams = [self.current_state.teamA, self.current_state.teamB]
            for i in range(2):
                team = teams[i]
                movs = movms[i]
                for player in TeamState.keyset:
                    #print 'GUAPAGUAPA:',movs[player].linearVelocity
                    team[player].linearVel = min(movs[player].linearVelocity,VLM)
                    team[player].angVel = min(movs[player].angVelocity,VAM)

    def clock(self):
        self.timer = Timer(self.timeout, self.clock)
        self.timer.start()
        self.time += self.timeout
        
        self.applyMovements()
        self.phisics.compute(self.current_state, self.timeout, relocate=0)
        
        self.net_server.sendState(self.time, self.current_state)
